package com.gis.postgis.geojson.deserializer;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.BeanProperty;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonDeserializer;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.gis.postgis.geojson.parsers.FeatureCollectionGeoJsonParser;
import com.gis.postgis.geojson.parsers.FeatureGeoJsonParser;
import com.gis.postgis.geojson.parsers.GeoJsonBaseParser;
import com.gis.postgis.geojson.parsers.GeometryCollectionGeoJsonParser;
import com.google.common.collect.Maps;

import static com.gis.postgis.geojson.GeoJson.FEATURE;
import static com.gis.postgis.geojson.GeoJson.FEATURE_COLLECTION;
import static com.gis.postgis.geojson.GeoJson.GEOMETRY_COLLECTION;
import static com.gis.postgis.geojson.GeoJson.TYPE;

/**
 * 〈功能简述〉<br>
 * 〈〉
 *
 * @author Mr.QL
 * @ClassName GeoJsonDeserializer
 * @Date 2022-03-05 13:44
 * @Version 1.0
 */
public class GeoJsonDeserializer<T> extends JsonDeserializer<T> implements ContextualDeserializer {


    private Map<String, GeoJsonBaseParser<T>> parsers;

    public GeoJsonDeserializer() {

    }

    @Override
    public T deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        ObjectMapper mapper = (ObjectMapper) jsonParser.getCodec();
        //ObjectCodec oc = jsonParser.getCodec();
        ObjectNode nodeObject = (ObjectNode) mapper.readTree(jsonParser);
        JsonNode jsonNode = nodeObject.get(TYPE);
        String typeName = jsonNode.asText();
        GeoJsonBaseParser<T> parser = parsers.get(typeName);
        if (parser != null) {
            jsonParser = mapper.treeAsTokens(nodeObject);
            return parser.deserialize(jsonParser);
        } else {
            throw new JsonMappingException("Invalid Feature type: " + typeName);
        }
    }


    @Override
    public JsonDeserializer<T> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
        /**
         * 获取反序列化泛型类型
         */
        JavaType valueType = ctxt.getContextualType() != null
                ? ctxt.getContextualType()
                : property.getMember().getType();
        GeoJsonDeserializer deserializer = createDeserializer(valueType);
        return deserializer;
    }

    /**
     * 构建序反列化器
     *
     * @param valueType
     * @return
     */
    private GeoJsonDeserializer createDeserializer(JavaType valueType) {
        GeoJsonDeserializer deserializer = new GeoJsonDeserializer();
        Class<? extends GeoJsonDeserializer> deserializeClazz = deserializer.getClass();
        parsers = Maps.newHashMapWithExpectedSize(10);
        parsers.put(FEATURE, new FeatureGeoJsonParser<T>(valueType, deserializeClazz));
        parsers.put(FEATURE_COLLECTION, new FeatureCollectionGeoJsonParser<T>(valueType, deserializeClazz));
        parsers.put(GEOMETRY_COLLECTION, new GeometryCollectionGeoJsonParser<T>(valueType, deserializeClazz));
        deserializer.parsers = parsers;
        return deserializer;
    }

}
